/**
 * @dev Poll on each block to read data
 */

// import {ref} from 'vue';
import { Contract } from '@/utils/ethers';
import UserStore from "@/store/UserStore";
// import WalletStore from "@/store/WalletStore";
import WalletStore from "@/store/WalletStore";
import Dialog from "@/components/dialog/dialog";
import { ROBOT_ADDRESS, GAP_PRICE, GAP_LIMIT } from '@/utils/constants'
import { formatEther, parseUnits } from '@/utils/ethers'
import { EventFilter } from "ethers";
import { generateTokenApi } from "@/api/system/user";
import storage from "@/utils/storage";
import { storeToRefs } from "pinia";
import useWalletHook from "@/hooks/Wallet";

// Most recent data read is saved as state
// const lastBlockNumber = ref<number>(0);
// const lastBlockTimestamp = ref<number>(0);
// const ethBalance = ref<bigint>();

export default function useContractHook () {
  // async function poll(multicall: Contract) {
  //     // Don't poll if user has not connected wallet
  //     if (!walletAddress.value) return;
  //
  //     // Define calls to be read using multicall
  //     const calls = [
  //         {target: MULTICALL_ADDRESS, callData: multicall.interface.encodeFunctionData('getCurrentBlockTimestamp')},
  //         {
  //             target: MULTICALL_ADDRESS,
  //             callData: multicall.interface.encodeFunctionData('getEthBalance', [walletAddress.value])
  //         }, // prettier-ignore
  //     ];
  //
  //     // Execute calls
  //     const {blockNumber, returnData} = await multicall.tryBlockAndAggregate(false, calls);
  //
  //     // Parse return data
  //     const [timestampEncoded, ethBalanceEncoded] = returnData;
  //     const {timestamp} = multicall.interface.decodeFunctionResult('getCurrentBlockTimestamp', timestampEncoded.returnData); // prettier-ignore
  //     const {balance} = multicall.interface.decodeFunctionResult('getEthBalance', ethBalanceEncoded.returnData); // prettier-ignore
  //
  //     // Save off data
  //     lastBlockNumber.value = (blockNumber as BigNumber).toNumber();
  //     lastBlockTimestamp.value = (timestamp as BigNumber).toNumber();
  //     ethBalance.value = (balance as BigNumber).toBigInt();
  // }

  function checkWallet () {
    const walletStore = WalletStore()
    const { _walletAddress } = storeToRefs(walletStore)
    if (!_walletAddress.value) {
      // TODO 待国际化
      Dialog('wallet address can not be empty')
      return
    }
  }

  /**
   *
   * @param address contract address
   * @param abi
   * @param txid transaction id
   */
  async function withdraw (address: string, abi: string[], txid: string) {
    // Don't poll if user has not connected wallet
    checkWallet()

    // if(!window.ethereum) return
    // // @ts-ignore
    // const provider = new ethers.providers.Web3Provider(window.ethereum)
    // const signer = provider.getSigner()
    // const contract = new Contract(address, abi, signer)

    // const {provider} = useWalletHook()
    // console.log('getTokenBalance provider:', provider.value)
    // const signer = provider.value?.getSigner();

    const walletStore = WalletStore()
    const { _provider } = storeToRefs(walletStore)
    const signer = _provider.value.getSigner()
    // const contract = new Contract(address, abi, _signer.value)
    const contract = new Contract(address, abi, signer)

    console.log('contract', contract)
    // console.log('before, signer:', _signer.value)
    console.log('before, signer:', signer)
    const options = {
      gasPrice: GAP_PRICE,
      gasLimit: GAP_LIMIT
    }
    console.log('txid:', txid)
    try {
      const tx = await contract.withdraw(txid, options)
      console.log('after,tx:', tx)
      const receipt = await tx.wait()
      console.log('withdraw receipt:', receipt)
      return receipt.transactionHash
    } catch (error) {
      // TODO
      // @ts-ignore
      console.log('withdraw error:', error.message);
      // @ts-ignore
      Dialog(error.message)
      return null
    }
  }

  async function startPolling () {
    // const walletStore = WalletStore()
    // const {_walletAddress} = storeToRefs(walletStore)
    const { walletAddress } = useWalletHook()

    console.log('walletAddress', walletAddress)

    await generateTokenApi({
      upline: storage.getItem('inviteCode') ? storage.getItem('inviteCode') : '',
      // username: _walletAddress.value
      username: walletAddress.value
    }).then((res: any) => {
      console.log('generateTokenApi res:', res)
      const userStore = UserStore()
      userStore.setToken(res.apiToken)
      const userInfo = {
        inviteCode: res.shareCode,
        link: res.shortCode,
        userLevel: res.userLevel,
        tgId: res.tgId,
        dcId: res.dcId
      }
      userStore.setUserInfo(userInfo)
      if (storage.getItem('inviteCode')) {
        storage.removeItem('inviteCode')
      }
    })
  }

  // /**
  //  * 交易
  //  *
  //  * @param from 发送方钱包地址
  //  * @param to 接收方钱包地址
  //  * @param fromPrivateKey 发送方钱包私钥
  //  * @param amount 转账金额
  //  */
  // async function transaction (from: string, to: string, fromPrivateKey: string, amount: string) {
  //   const senderWallet = new ethers.Wallet(fromPrivateKey, provider.value)
  //   const tx = await senderWallet.sendTransaction({
  //     to: to,
  //     value: parseEther(amount)
  //   })
  //   // 等待交易完成
  //   await tx.wait()
  //   console.log('transaction:', tx)
  // }

  /**
   * 转账
   *
   * @param address 合约地址
   * @param abi 合约abi数组
   * @param to 转账的钱包地址
   * @param amount 转账金额
   */
  async function transaction (address: string, abi: string[], to: string, amount: string) {
    checkWallet()

    const walletStore = WalletStore()
    const { _signer, _walletAddress } = storeToRefs(walletStore)

    const contract = new Contract(address, abi, _signer.value)
    console.log('format amount:', formatEther(amount))
    const balance = await contract.balanceOf(_walletAddress.value)
    const amountFormatted = parseUnits(amount, 6)
    // if(amount.isNegative()){
    //
    // }
    if (balance.lt(amountFormatted)) {
      // TODO 提示余额不足
      console.log('Insufficient balance')
      return
    }
    const tx = contract.transfer(to, amountFormatted, { gasPrice: GAP_PRICE })
    const receipt = await tx.wait()
    console.log('transfer receipt:', receipt)
  }

  /**
   * 查询余额
   *
   */
  async function getBalance () {
    checkWallet()

    const walletStore = WalletStore()
    const { _provider, _walletAddress } = storeToRefs(walletStore)

    const _balance = await _provider.value?.getBalance(_walletAddress.value)
    // console.log('get balance res:', formatUnits(_balance, 6))
    console.log('get balance res:', formatEther(_balance))
    return formatEther(_balance)
  }

  /**
   *  查询币种
   *
   * @param address 合约地址
   * @param abi 合约abi数组
   */
  async function symbol (address: string, abi: string[]) {
    const walletStore = WalletStore()
    const { _provider } = storeToRefs(walletStore)
    const contract = new Contract(address, abi, _provider.value)
    return await contract.symbol()
  }

  /**
   *  查询币的总额
   *
   * @param address 合约地址
   * @param abi 合约abi数组
   */
  async function getTotalSupply (address: string, abi: string[]) {
    const walletStore = WalletStore()
    const { _provider } = storeToRefs(walletStore)
    const contract = new Contract(address, abi, _provider.value)
    console.log('total supply res:', await contract.totalSupply())
    return await contract.totalSupply()
  }

  /**
   * 查询事件
   *
   * @param address 合约地址
   * @param abi 合约abi数组
   * @param event 事件名称
   */
  async function queryEvent (address: string, abi: string[], event: EventFilter) {
    const walletStore = WalletStore()
    const { _provider } = storeToRefs(walletStore)
    const contract = new Contract(address, abi, _provider.value)
    const block = await _provider.value?.getBlockNumber()
    const events = await contract.queryFilter(event, block - 10, block)
    console.log('queryEvent:', events)
  }

  /**
   * 获取代币的授权额度
   * @param address 合约地址
   * @param abi 合约abi数组
   */
  function getApproveAllowance (address: string, abi: string[]) {
    checkWallet()

    const walletStore = WalletStore()
    const { _provider, _walletAddress } = storeToRefs(walletStore)

    const contract = new Contract(address, abi, _provider.value)
    return new Promise((resolve) => {
      const allowance = contract.allowance(_walletAddress.value, ROBOT_ADDRESS)
      console.log('getApproveAllowance res:', allowance)
      resolve(formatEther(allowance))
    })
  }

  async function getTokenBalance (address: string, abi: string[]) {
    // if (!window.ethereum) return
    //
    // // @ts-ignore
    // const provider = new ethers.providers.Web3Provider(window.ethereum)
    // const signer = provider.getSigner()

    const { provider } = useWalletHook()
    console.log('getTokenBalance provider:', provider.value)
    const signer = provider.value?.getSigner();
    const walletAddress = await signer?.getAddress()
    console.log('getTokenBalance signer:', walletAddress)
    const contract = new Contract(address, abi, provider.value)
    // console.log('getTokenBalance addr:', signer.value.getAddress())
    const balance = await contract.balanceOf(walletAddress)
    console.log('balance:', balance)
    return balance / 100000000
  }

  return {
    // Methods
    startPolling,
    getBalance,
    transaction,
    getTotalSupply,
    symbol,
    queryEvent,
    getApproveAllowance,
    getTokenBalance,
    withdraw
    // Data
    // lastBlockNumber,
    // lastBlockTimestamp,
    // ethBalance,
  };
}
